/*################################################################
# TRABAJO PRACTICO Nº2                                           #
# EJERCICIO 5                                                    #
# Primera reentrega                                              #
# ALUMNOS                                                        #
# Alonso, Rodolfo                            DNI: 33.474.354     #
# Barrera, Lourdes                           DNI: 33.306.634     #
# Gomez, Ezequiel                            DNI: 35.274.172     #
# Mahiques, Pablo                            DNI: 33.834.348     #
# Sanchez, Martín                            DNI:                #
################################################################*/

extern "C"
{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <signal.h>

    #include <limits.h>
}

#include <vector>
using std::vector;

#include "eje5_comun.h"

void comprobar_argumentos(const int argc, const char** argv);
int iniciar_conexion(const int pid);
void generar_informe();
void salir (int exit_code);
void handler (int);

PID_FIFO servidor = {};
PID_FIFO datos = {};

vector<int> valores;


int main(const int argc, const char** argv)
{
    comprobar_argumentos(argc, argv);

    for(int sig=1; sig<32; sig++) signal(sig, SIG_IGN);
    if (signal(SIGTERM, handler) == SIG_ERR)
    {
        printf("Error al instalar manejador de senial SIGTERM");
        exit(1);
    }

    //Abrimos el FIFO para iniciar la conexion con el servidor
    strcpy(servidor.nombre_fifo, argv[1]);
    servidor.pid  = 0; //Desconocido por ahora
    servidor.fifo = abrir_fifo(servidor.nombre_fifo, 0666, O_RDWR, 0);

    //Abrimos el FIFO para recibir datos desde el servidor
    strcpy(datos.nombre_fifo, nombre_fifo_cliente(getpid()));
    datos.pid = 0; //Desconocido por ahora
    datos.fifo = abrir_fifo(datos.nombre_fifo, 0666, O_RDWR, 1);

    //Se informa al servidor cual es nuestro pid y se recibe el del servidor
    servidor.pid = datos.pid = iniciar_conexion( getpid() );

    //Bucle principal
    for(;;)
    {
        MENSAJE msg;

        if( leer_mensaje(datos.fifo, &msg) != 0 )
        {
            //Salimos del bucle si se produce un error al recibir
            break;
        }

        printf("CLIENTE %d Recibido dato: %d\n", getpid(), msg.dato);

        /* Estadisticas */
        valores.push_back(msg.dato);
    }

    //Nunca se debería terminar por aquí (a no ser que haya errores)
    salir(-100);
}


void comprobar_argumentos(const int argc, const char** argv)
{
    if (argc != 2)
    {
       printf("Error en la invocacion.\nUso: %s NOMBREFIFO\n", argv[0]);
       exit(1);
    }
}


int iniciar_conexion(const int pid)
{
	printf("Inciando conexion proceso [%d]\n", pid);

    MENSAJE msg = {pid};

    //Salida por FIFO: informamos el PID de este cliente
    if( write(servidor.fifo, &msg, sizeof(msg)) < 0 )
        return -1;

    //Entrada por FIFO: recibimos el PID del servidor
    if( read(datos.fifo, &msg, sizeof(msg)) < 0 )
        return -2;

    return msg.dato;
}


void salir(int exit_code)
{
    kill(servidor.pid, SIGTERM);
    servidor.pid = 0;

    cerrar_fifo(servidor.fifo, servidor.nombre_fifo);
    servidor.fifo = 0;
    servidor.nombre_fifo[0] = '\0';

    cerrar_fifo(datos.fifo, datos.nombre_fifo);
    datos.fifo = 0;
    datos.nombre_fifo[0] = '\0';

    generar_informe();

    exit(exit_code);
}


void handler (int signum)
{
    if(signum==SIGTERM)
    {
        salir(0);
    }
}


void generar_informe()
{
	char nombre_informe[255];
	sprintf(nombre_informe, "informe_%d.txt", getpid());

	FILE* f = fopen(nombre_informe, "w");

    if(valores.size() == 0)
    {
        fprintf(f, "CLIENTE %d: No se recibieron valores", getpid());
        return;
    }

    fprintf(f, "CLIENTE %d\n", getpid());

    int suma_total = 0;
    int mas_grande = valores[0];
    int mas_chico  = valores[0];

    fprintf(f, "Valores recibidos: ");
    for(vector<int>::iterator it = valores.begin();
        it != valores.end();
        ++it)
    {
        if(it != valores.begin())
            fprintf(f, ", ");
        fprintf(f, "%d", *it);

        if( *it > mas_grande ) mas_grande = *it;
        if( *it < mas_chico  ) mas_chico  = *it;

        suma_total += *it;
    }
    fprintf(f, "\n");
    
    fprintf(f, "Numero mas grande: %d\n", mas_grande);
    fprintf(f, "Numero mas chico: %d\n", mas_chico);
    fprintf(f, "Numero promedio: %.2f\n", suma_total/(double)valores.size());

    fclose(f);
}
